#include "MyThreadPoll.h"


MyThreadPoll::MyThreadPoll(int threadNum) : m_threadCnt(threadNum)
{
    start();        // 初始化线程
}

void MyThreadPoll::start()
{
    m_isStart = true;
    m_threadVec.reserve(m_threadCnt);
    for (int i=0; i<m_threadCnt; i++)
    {
        // 每个线程都执行同样的代码片段, 去读取任务队列中的任务; 有任务时就读取, 没有则休眠等待
        m_threadVec.push_back(std::move(new std::thread(&MyThreadPoll::threadLoop, this)));             // 不一定是静态成员函数
    }
}

MyThreadPoll::~MyThreadPoll()
{
    if ( m_isStart )
    {
        stop();
    }
}

void MyThreadPoll::addTask(const task_t &task)
{
    printf("[ MyThreadPoll::%s ]\n", __FUNCTION__);
    lock_guard<mutex> m_lockguard(m_mutex);
    m_taskQueue.push_back(task);
    m_conditonVar.notify_one();     // 添加任务后通知空闲线程开始执行任务
}

void MyThreadPoll::threadLoop()
{
    printf("Thread id [ %s ] start.\n", getThreadId().c_str());

    while (m_isStart)
    {
        // 有任务， 并且任务函数已经初始化时， 执行任务函数
        task_t task;
        if ( getTask(task) )
        {
            task();
        }
    }

    printf("Thread id [ %s ] exit.\n", getThreadId().c_str());
}

bool MyThreadPoll::getTask(task_t &task)
{
    unique_lock<mutex> m_uniquelock(m_mutex);

    // 避免虚假唤醒, 先判断共享资源的有效性, 不满足条件则继续阻塞等待
    while ( m_isStart && m_taskQueue.empty() )
    {
        m_conditonVar.wait(m_uniquelock);
    }

    printf("Thread id [ %s ] wake up.\n", getThreadId().c_str());

    // 取出第一个任务
    if ( !m_taskQueue.empty() && m_isStart )
    {
        task = m_taskQueue.front();
        m_taskQueue.pop_front();
    }

    return task.operator bool();                // 任务是否有效
}

string MyThreadPoll::getThreadId()
{
    std::stringstream tmp;
    tmp << std::this_thread::get_id();
    return tmp.str();
}

void MyThreadPoll::stop()
{
    printf("MyThreadPoll::%s .\n", __FUNCTION__);
    {
        // 互斥锁， {}作用域结束后锁进行释放
        unique_lock<mutex> m_uniquelock(m_mutex);
        m_isStart = false;
        m_conditonVar.notify_all();

        printf("Notify all.\n");
    }

    // 删除全部线程
    auto iter = m_threadVec.begin();
    while( iter != m_threadVec.end() )
    {
        (*iter)->join();
        iter = m_threadVec.erase(iter);
    }
    m_threadVec.clear();
}
